﻿using System.Collections.Generic;
using System.IO;
using System.Text;
using KBEngine.Setting.TypeDef;

namespace KBEngine.Export
{
    public class UserTypeExport: PythonExport
    {
        List<BaseType> m_types;
        public UserTypeExport(List<BaseType> types)
        {
            m_types = types;
        }
        public bool Save(string dir)
        {
            //TODO:flaot->映射成什么类型还需要额外信息,暂时定义文件只输出不存在的
            var dicWriterByFile = new Dictionary<string, CodeWriter>();
            foreach (var type in m_types)
            {
                var userType = type as UserType;
                if (userType == null || string.IsNullOrEmpty(userType.ImplementedBy))
                    continue;

                var modulePath = userType.ImplementedBy.Split('.');
                if (modulePath.Length != 2)
                    throw new System.ArgumentException($"{type.TypeName} {userType.ImplementedBy} impl error! like:[moduleName.ClassName|moduleName.xxInstance]");

                bool exist;
                if (!(exist = dicWriterByFile.TryGetValue(modulePath[0], out var codeWriter)))
                { 
                    codeWriter = new CodeWriter(fileMark: "# -*- coding: utf-8 -*-");
                    dicWriterByFile.Add(modulePath[0], codeWriter);
                }
                GeneratePythonCode(exist, codeWriter, modulePath[1], userType);
            }
            foreach (var item in dicWriterByFile)
            {
                var file = Path.Combine(dir, item.Key + ".py");
                if(!File.Exists(file))
                    item.Value.Save(file, encoding: Encoding.UTF8);
            }
            return true;
        }

        void GeneratePythonCode(bool exist, CodeWriter codeWriter, string varOrPicklerName, UserType type)
        {
            var isVar = char.IsLower(varOrPicklerName[0]);//是否是实列名称(小写为变量 大写为PICKLER)
            var picklerName = isVar ? type.TypeName + "_PICKLER" : varOrPicklerName;
            var mapClassName = GetTName(type.TypeName);

            if (!exist)
            { 
                codeWriter.Writeln("import KBEngine");
                codeWriter.Writeln("import GlobalConst");
                codeWriter.Writeln("from KBEDebug import * ");
            }
            codeWriter.Writeln();
            codeWriter.Writeln();
            codeWriter.Writeln($"class {mapClassName}(dict):");
            codeWriter.IncIndent();
            codeWriter.Writeln("def __init__(self):");
            codeWriter.IncIndent();
            codeWriter.Writeln("dict.__init__(self)");
            codeWriter.DecIndent();
            codeWriter.Writeln();

            //asDict
            codeWriter.Writeln("def asDict(self):");
            codeWriter.IncIndent();
            codeWriter.Writeln("dct = {");
            codeWriter.IncIndent();
            foreach (var item in type.Properties)
            {
                codeWriter.Writeln($"\"{item.FieldName}\": self[\"{item.FieldName}\"],");
            }
            codeWriter.DecIndent();
            codeWriter.Writeln("}");
            codeWriter.Writeln("return dct");
            codeWriter.DecIndent();
            codeWriter.Writeln();

            //createFromDict
            codeWriter.Writeln(@"def createFromDict(self, dictData):");
            codeWriter.IncIndent();
            foreach (var item in type.Properties)
            {
                codeWriter.Writeln($"self[\"{item.FieldName}\"] = dictData[\"{item.FieldName}\"]");
            }
            codeWriter.Writeln(@"return self");
            codeWriter.Writeln();
            codeWriter.DecIndent();
            codeWriter.DecIndent();

            //PICKLER
            codeWriter.Writeln();
            codeWriter.Writeln($"class {picklerName}:");
            codeWriter.IncIndent();
            codeWriter.Writeln("def __init__(self):");
            codeWriter.IncIndent();
            codeWriter.Writeln("pass");
            codeWriter.DecIndent();
            codeWriter.Writeln();
            //PICKLER.createObjFromDict
            codeWriter.Writeln("def createObjFromDict(self, dct):");
            codeWriter.IncIndent();
            codeWriter.Writeln($"return {mapClassName}().createFromDict(dct)");
            codeWriter.DecIndent();
            codeWriter.Writeln();
            //PICKLER.getDictFromObj
            codeWriter.Writeln("def getDictFromObj(self, obj):");
            codeWriter.IncIndent();
            codeWriter.Writeln("return obj.asDict()");
            codeWriter.DecIndent();
            codeWriter.Writeln();
            //PICKLER.isSameType
            codeWriter.Writeln("def isSameType(self, obj):");
            codeWriter.IncIndent();
            codeWriter.Writeln($"return isinstance(obj, {mapClassName})");
            codeWriter.DecIndent();
            codeWriter.DecIndent();
            codeWriter.Writeln();

            //inst
            if (isVar)
            {
                codeWriter.Writeln();
                codeWriter.Writeln($"{varOrPicklerName} = {picklerName}()");
            }
        }
        string GetTName(string typeName)
        {
            StringBuilder sb = new StringBuilder(typeName.ToLower());
            for (int i = sb.Length - 1; i >= 0; --i)
            {
                if (sb[i] != '_')
                    continue;

                sb.Remove(i, 1);
                if (sb.Length > i)
                    sb[i] = char.ToUpper(sb[i]);
            }
            sb[0] = char.ToUpper(sb[0]);
            sb.Insert(0, 'T');
            return sb.ToString();
        }
    }
}
